﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace CMS6Tools.IISServer
{
    public partial class IISServerForm : Form
    {
        static DateTime MinDateTime = new DateTime(2015, 1, 1);
        public List<RequestInfo> RequestInfoList { get; private set; }
        public PerformanceCounter CpuCounter { get; private set; }
        public long TimeElapsed { get; private set; }
        public bool Started { get; private set; }
        public bool killed = false; 

        public IISServerForm()
        {
            InitializeComponent();
            RequestInfoList = new List<RequestInfo>();
        }

        private void StartButton_Click(object sender, EventArgs e)
        { 
            if (!Started)
            {
                Started = true;
                RequestInfoChart.ChartAreas[0].AxisX.Maximum = int.Parse(DurationTextBox.Text) * 60;
                StartButton.Enabled = false;
                StartButton.Text = "Resume";
                StopButton.Enabled = true;
                StartLabel.Text = string.Format("Start : {0}", DateTime.Now);
                CpuCounter.MachineName = ServerNameTextBox.Text;
            }


            RequestTimer.Interval = Int32.Parse(IntervalTextBox.Text ?? "1000");
            if (RequestTimer.Interval < 1000)
                RequestTimer.Interval = 1000;
            RequestTimer.Start();
        }

        void RequestTimer_Tick(object sender, EventArgs e)
        {
            var currentProcess = Process.GetCurrentProcess();
            var currentMemorySize = currentProcess.PrivateMemorySize64;
            if (currentMemorySize > Int32.Parse(MaxMemoryTextBox.Text) * 1024 * 1024)
            {
                SaveDataToFile();
                killed = true;
                currentProcess.Kill();
                return;
            }

            TimeElapsed += (RequestTimer.Interval/1000);
            if (TimeElapsed > RequestInfoChart.ChartAreas[0].AxisX.Maximum)
            {
                RequestInfoChart.ChartAreas[0].AxisX.Maximum += int.Parse(DurationTextBox.Text) * 60;

                SaveDataToFile();
            }

            var counterByWorker = new Dictionary<string, int>();
            var urls = new List<string>();
            var homeCount = 0;
            var requestDataListCount = 0;
            var cpuUsage = 0.0f;
            try
            {
                //System.Management.ManagementEventWatcher managementEventWatcher = new System.Management.ManagementEventWatcher();
               
                cpuUsage = CpuCounter.NextValue();
                var requestDataList = new List<RequestData>();
                using (var serverManager = Microsoft.Web.Administration.ServerManager.OpenRemote(ServerNameTextBox.Text.Trim()))
                {
                    var workProcesses = serverManager.WorkerProcesses;
                    foreach (var workProcess in workProcesses)
                    {
                        var count = 0;
                        foreach (var request in workProcess.GetRequests(0))
                        {
                            var requestData = new RequestData();
                            requestData.WorkProcessName = workProcess.AppPoolName;
                            requestData.Client = request.ClientIPAddr;
                            requestData.Module = request.CurrentModule;
                            requestData.Stage = request.PipelineState.ToString();
                            requestData.TimeElapsed = request.TimeElapsed;
                            requestData.Url = request.Url;
                            requestData.ConnectionId = request.ConnectionId;
                            requestDataList.Add(requestData);
                            
                            var url = request.Url.TrimEnd('/');
                            if (MonitorURLsCheckBox.Checked)
                                urls.Add(request.Url+":"+workProcess.AppPoolName);

                            if (url.Length == 0 || url.Equals("/home", StringComparison.InvariantCultureIgnoreCase))
                            {
                                homeCount++;
                            }

                        }
                        counterByWorker[workProcess.AppPoolName] = count;
                    }
                }
                requestDataListCount = requestDataList.Count;
                RequestsDataGridView.DataSource = requestDataList;
            }
            catch
            {
                requestDataListCount = 0;
            }
            RequestInfoChart.Series[0].Points.AddXY(TimeElapsed, requestDataListCount);
            RequestInfoChart.Series[1].Points.AddXY(TimeElapsed,cpuUsage );
            RequestInfoList.Add(new RequestInfo
            {
                Time = (long)DateTime.Now.Subtract(MinDateTime).TotalSeconds,
                Requests = requestDataListCount,
                CPU = (float)Math.Round((double)cpuUsage, 2),
                CountByWorker = counterByWorker,
                URLs = urls,
                HomeCount = 0
            });

        }

        private void StopButton_Click(object sender, EventArgs e)
        {
            RequestTimer.Stop();

            StartButton.Enabled = true;
        }

        private void IISServerForm_Load(object sender, EventArgs e)
        {
            StopButton.Enabled = false;

            ServerNameTextBox.Text = Environment.MachineName;
            RequestTimer.Interval = 1000;
            RequestTimer.Tick += RequestTimer_Tick;

            CpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
            
            RequestInfoChart.ChartAreas[0].AxisX.Maximum = int.Parse(DurationTextBox.Text) * 60;
            //RequestInfoChart.ChartAreas[0].AxisX.Interval = RequestTimer.Interval / 1000;
            RequestInfoChart.ChartAreas[0].AxisY2.Maximum = 100;

            RequestInfoChart.ChartAreas[0].AxisY2.LineColor = Color.Transparent;
            RequestInfoChart.ChartAreas[0].AxisY2.MajorGrid.Enabled = false;
            RequestInfoChart.ChartAreas[0].AxisY2.Enabled = System.Windows.Forms.DataVisualization.Charting.AxisEnabled.True;
            RequestInfoChart.ChartAreas[0].AxisY2.IsStartedFromZero = RequestInfoChart.ChartAreas[0].AxisY.IsStartedFromZero;            
            
            //RequestInfoChart.ChartAreas[0].AxisY.Maximum = 100;
        }

        private void SaveDataToFile()
        {
            if (!SaveToFileCheckBox.Checked)
                return;

            var folder = Path.Combine( Environment.CurrentDirectory,"Data");
            if (!Directory.Exists(folder))
                Directory.CreateDirectory(folder);
            var fileName = DateTime.Now.ToString("yyyyMMddHHmmss") + ".txt";
            using(var streamWriter = new StreamWriter(Path.Combine(folder,fileName)))
            {
                var stringBuilder = new StringBuilder();
                foreach (var info in RequestInfoList)
                {
                    stringBuilder.Clear();
                    if (MonitorURLsCheckBox.Checked)
                    {
                        var urlStr = info.URLs.Any() ? info.URLs.Aggregate((a, b) => string.Format("{0},{1}", a, b)).Trim(',') : string.Empty;
                        stringBuilder.AppendFormat("{0},{1},{2},\"{3}\"", info.Time, info.Requests, info.CPU, urlStr);
                    }
                    else
                    {
                        stringBuilder.AppendFormat("{0},{1},{2}", info.Time, info.Requests, info.CPU);
                    }
                    streamWriter.WriteLine(stringBuilder.ToString());
                }
            }
            RequestInfoList.Clear();
        }

        private void IISServerForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (!killed)
                SaveDataToFile();
        }

        private void MergeDataFilesButton_Click(object sender, EventArgs e)
        {
            var path = @"E:\_Misc Projects\Concurrent";
            var directoryInfo = new DirectoryInfo(path);
            foreach (var subDirectory in directoryInfo.GetDirectories())
            {
                using (var streamWriter = new StreamWriter(Path.Combine(subDirectory.Parent.FullName, subDirectory.Name + ".csv"), false))
                {
                    foreach (var fileInfo in subDirectory.GetFiles())
                    {
                        using (var fileStream = fileInfo.OpenRead())
                        using (var streamReader = new StreamReader(fileStream))
                        {
                            while (!streamReader.EndOfStream)
                            {
                                var line = streamReader.ReadLine();
                                var args = line.Split(',');
                                try
                                {
                                    var datetimeSpan = TimeSpan.FromSeconds(Int32.Parse(args[0])); // seconds
                                    var date = MinDateTime.Add(datetimeSpan);
                                    streamWriter.WriteLine(string.Format("{0},{1},{2}", date.ToString("MM/dd/yyyy HH:mm:ss"), args[1], args[2]));
                                }
                                catch { }
                            }
                        }
                    }
                }
            }
            MessageBox.Show("DONE");
        }

        private void ShowChartButton_Click(object sender, EventArgs e)
        {
            var showChartForm = new ShowChartForm();
            showChartForm.ShowDialog();
        }
    }

    public class RequestData
    {
        public string WorkProcessName { get; set; }
        public string ConnectionId { get; set; }
        public string Url { get; set; }
        public string Client { get; set; }
        public string Stage { get; set; }
        public string Module { get; set; }
        public int TimeElapsed { get; set; }
    }

    public class RequestInfo
    {
        public RequestInfo()
        {
            URLs = new List<string>();
            CountByWorker = new Dictionary<string, int>();
        }

        public long Time { get; set; }
        public int Requests { get; set; }
        public float CPU { get; set; }
        public int HomeCount { get; set; }
        /// <summary>
        /// Get the count by each IIS worker process
        /// </summary>
        public Dictionary<string, int> CountByWorker { get; set; }

        public List<string> URLs { get; set; }
    }
}
